import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository, In } from 'typeorm'
import { format } from 'date-fns'
import { Pagination } from '~/helper/paginate/pagination'
import { paginate } from '~/helper/paginate'
import { MultipartFile } from '@fastify/multipart'
import { CreateWorkDto } from './dto/create-wall.dto'
import { UpdateWorkDto } from './dto/update-wall.dto'
import { WorkEntity, WorkType, WorkStatus } from './entities/wall.entity'
import { WorkTagEntity } from './entities/work-tag.entity'
import { WorkTagRelationEntity } from './entities/work-tag-relation.entity'
import { WorkCommentEntity } from './entities/work-comment.entity'
import { QueryWorkDto } from './dto/query-work.dto'
import { UploadWorkDto } from './dto/upload-work.dto'
import { CreateCommentDto } from './dto/create-comment.dto'
import { 
  fileRename, 
  getExtname, 
  getFileType, 
  getFilePath, 
  saveLocalFile,
  getName,
  getSize
} from '~/utils/file.util'
import * as path from 'path'
import * as fs from 'fs'

// 扩展MultipartFile类型以兼容前端提交的文件格式
interface ExtendedFile extends Partial<MultipartFile> {
  name?: string;
  base64?: string;
  buffer?: Buffer;
  [key: string]: any;
}

@Injectable()
export class WallService {
  constructor(
    @InjectRepository(WorkEntity)
    private readonly workRepository: Repository<WorkEntity>,
    @InjectRepository(WorkTagEntity)
    private readonly workTagRepository: Repository<WorkTagEntity>,
    @InjectRepository(WorkTagRelationEntity)
    private readonly workTagRelationRepository: Repository<WorkTagRelationEntity>,
    @InjectRepository(WorkCommentEntity)
    private readonly workCommentRepository: Repository<WorkCommentEntity>,
  ) {}

  /**
   * 创建作品
   */
  async create(createWorkDto: CreateWorkDto): Promise<WorkEntity> {
    // 生成作品编号
    const workId = await this.generateWorkId()

    // 创建作品
    const work = this.workRepository.create({
      ...createWorkDto,
      workId,
    })
    
    // 保存作品
    const savedWork = await this.workRepository.save(work)

    // 如果有标签，创建作品-标签关联
    if (createWorkDto.tagIds && createWorkDto.tagIds.length > 0) {
      const tagRelations = createWorkDto.tagIds.map((tagId) => ({
        workId: savedWork.id,
        tagId,
      }))
      await this.workTagRelationRepository.save(tagRelations)
    }

    return savedWork
  }

  /**
   * 获取作品列表
   */
  async findAll(query: QueryWorkDto): Promise<Pagination<WorkEntity>> {
    const { page = 1, pageSize = 10, workType, classId, status, tagId, tabType } = query

    // 构建基础查询
    const queryBuilder = this.workRepository.createQueryBuilder('work')
      .where('work.isDelete = :isDelete', { isDelete: 0 })
    
    // 根据作品类型过滤
    if (workType !== undefined) {
      queryBuilder.andWhere('work.workType = :workType', { workType })
    }
    
    // 根据tabType优化查询
    if (tabType === 'champion') {
      queryBuilder.andWhere('work.status = :status', { status: WorkStatus.Champion })
    }
    else if (tabType === 'popular') {
      // 针对popular排序，采用viewCount和likeCount的综合排序
      queryBuilder.orderBy('(work.viewCount * 0.7 + work.likeCount * 1.5)', 'DESC')
    }
    else if (tabType === 'theater') {
      // 针对theater标签，增加缓存支持
      queryBuilder
        .cache('wall_theater_list', 60000) // 1分钟缓存
    }

    if (classId) {
      queryBuilder.andWhere('work.classId = :classId', { classId })
    }

    if (status !== undefined) {
      queryBuilder.andWhere('work.status = :status', { status })
    }

    // 如果有标签过滤，使用子查询
    if (tagId) {
      queryBuilder.andWhere(qb => {
        const subQuery = qb
          .subQuery()
          .select('relation.workId')
          .from(WorkTagRelationEntity, 'relation')
          .where('relation.tagId = :tagId', { tagId })
          .getQuery()
        return `work.id IN ${subQuery}`
      })
    }

    // 设置默认排序（如果没有特殊排序）
    if (tabType !== 'popular') {
      queryBuilder.orderBy('work.createdAt', 'DESC')
    }

    // 执行分页查询
    const works = await paginate<WorkEntity>(queryBuilder, {
      page,
      pageSize,
    })

    // 如果有作品，获取标签和学生信息
    if (works.items.length > 0) {
      await this.enrichWorksWithTagsAndStudents(works.items)
    }

    return works
  }
  
  /**
   * 为作品列表添加标签和学生信息
   * 提取为单独方法以便复用和维护
   */
  private async enrichWorksWithTagsAndStudents(works: WorkEntity[]): Promise<void> {
    const workIds = works.map(work => work.id)
    
    // 获取所有作品的标签关联
    const tagRelations = await this.workTagRelationRepository.find({
      where: { workId: In(workIds) },
      cache: true // 使用缓存减少重复查询
    })
    
    if (tagRelations.length > 0) {
      // 获取所有标签
      const tagIds = [...new Set(tagRelations.map(relation => relation.tagId))]
      const tags = await this.workTagRepository.find({
        where: { id: In(tagIds), isDelete: 0 },
        cache: 60000 // 1分钟缓存
      })

      // 构建标签映射
      const tagMap = {}
      tags.forEach(tag => {
        tagMap[tag.id] = tag
      })

      // 构建作品-标签映射
      const workTagsMap = {}
      tagRelations.forEach(relation => {
        if (!workTagsMap[relation.workId]) {
          workTagsMap[relation.workId] = []
        }
        if (tagMap[relation.tagId]) {
          workTagsMap[relation.workId].push(tagMap[relation.tagId])
        }
      })

      // 将标签添加到作品
      works.forEach(work => {
        work['tags'] = workTagsMap[work.id] || []
      })
    }
    
    // 查询学生信息并添加到作品
    try {
      const studentIds = [...new Set(works.map(work => work.studentId))]
      const students = await this.workRepository.manager.query(
        `SELECT s.id, s.student_id as studentId, s.user_name as userName, 
               u.school, u.grade, c.class_name as className
         FROM c_student s
         LEFT JOIN c_user u ON s.user_id = u.id
         LEFT JOIN c_student_class sc ON s.id = sc.student_id
         LEFT JOIN c_class c ON sc.class_id = c.id
         WHERE s.id IN (?) AND s.is_delete = 0`,
        [studentIds]
      )
      
      // 构建学生映射
      const studentMap = {}
      students.forEach(student => {
        if (!studentMap[student.id]) {
          studentMap[student.id] = student
        }
      })
      
      // 将学生信息添加到作品
      works.forEach(work => {
        work['student'] = studentMap[work.studentId] || null
      })
    } catch (error) {
      console.error('获取学生信息失败:', error)
    }
  }

  /**
   * 获取单个作品
   */
  async findOne(id: number): Promise<WorkEntity> {
    const work = await this.workRepository.findOne({
      where: { id, isDelete: 0 }
    })

    if (!work) {
      throw new NotFoundException(`作品ID为${id}的记录不存在`)
    }

    // 获取作品标签
    const tagRelations = await this.workTagRelationRepository.find({
      where: { workId: id }
    })

    if (tagRelations.length > 0) {
      const tagIds = tagRelations.map(relation => relation.tagId)
      const tags = await this.workTagRepository.find({
        where: { id: In(tagIds), isDelete: 0 }
      })
      work['tags'] = tags
    } else {
      work['tags'] = []
    }

    // 获取学生信息
    try {
      const student = await this.workRepository.manager.query(
        `SELECT s.id, s.student_id as studentId, s.user_name as userName, 
                u.school, u.grade, c.class_name as className
         FROM c_student s
         LEFT JOIN c_user u ON s.user_id = u.id
         LEFT JOIN c_student_class sc ON s.id = sc.student_id
         LEFT JOIN c_class c ON sc.class_id = c.id
         WHERE s.id = ? AND s.is_delete = 0
         LIMIT 1`,
        [work.studentId]
      )
      
      if (student && student.length > 0) {
        work['student'] = student[0]
      }
    } catch (error) {
      console.error('获取学生信息失败:', error)
    }

    // 增加浏览次数
    await this.workRepository.update(id, {
      viewCount: work.viewCount + 1
    })

    return work
  }

  /**
   * 更新作品
   */
  async update(id: number, updateWorkDto: UpdateWorkDto): Promise<WorkEntity> {
    const work = await this.findOne(id)
    
    // 更新作品
    await this.workRepository.update(id, updateWorkDto)

    // 如果有更新标签
    if (updateWorkDto.tagIds) {
      // 删除旧标签关联
      await this.workTagRelationRepository.delete({ workId: id })
      
      // 创建新标签关联
      if (updateWorkDto.tagIds.length > 0) {
        const tagRelations = updateWorkDto.tagIds.map((tagId) => ({
          workId: id,
          tagId,
        }))
        await this.workTagRelationRepository.save(tagRelations)
      }
    }

    return this.findOne(id)
  }

  /**
   * 删除作品
   */
  async remove(id: number): Promise<void> {
    const work = await this.findOne(id)
    
    await this.workRepository.update(id, { isDelete: 1 })
  }

  /**
   * 生成作品ID
   */
  private async generateWorkId(): Promise<string> {
    const date = new Date()
    const prefix = 'WK' + format(date, 'yyyyMMdd')
    
    // 查询当天最大的作品ID
    const latestWork = await this.workRepository
      .createQueryBuilder('work')
      .where('work.workId LIKE :prefix', { prefix: `${prefix}%` })
      .orderBy('work.workId', 'DESC')
      .getOne()
    
    let sequence = 1
    if (latestWork) {
      const latestSequence = parseInt(latestWork.workId.substring(prefix.length), 10) || 0
      sequence = latestSequence + 1
    }
    
    // 格式化为4位数，不足前面补0
    return `${prefix}${sequence.toString().padStart(4, '0')}`
  }

  /**
   * 上传作品
   */
  async uploadWork(file: MultipartFile | ExtendedFile, cover: MultipartFile | ExtendedFile, uploadWorkDto: UploadWorkDto): Promise<WorkEntity> {
    console.log('开始处理文件上传请求，验证基本参数...');
    
    if (!file) {
      throw new BadRequestException('文件不能为空')
    }

    // 检查是否使用默认封面
    const isDefaultCover = cover && cover.filename === '默认封面.jpg';
    console.log('是否使用默认封面:', isDefaultCover ? '是' : '否');

    console.log('处理主要作品文件...');
    // 处理作品文件
    let originalName = '', buffer;
    const startTime = Date.now();
    
    // 处理标准MultipartFile对象
    try {
      if (typeof file.toBuffer === 'function') {
        originalName = file.filename;
        buffer = await file.toBuffer();
        console.log(`标准文件对象处理完成，文件名: ${originalName}, 缓冲区大小: ${buffer.length} 字节`);
      } 
      // 处理JSON格式的文件对象
      else {
        originalName = (file as ExtendedFile).name || file.filename || 'unknown';
        console.log(`非标准文件对象，使用名称: ${originalName}`);
        
        // 如果前端提供的是base64字符串
        if ((file as ExtendedFile).base64) {
          const base64Data = (file as ExtendedFile).base64?.split(';base64,').pop() || '';
          buffer = Buffer.from(base64Data, 'base64');
          console.log(`从base64创建缓冲区，大小: ${buffer.length} 字节`);
        } 
        // 如果前端提供的是Buffer或其他格式
        else if ((file as ExtendedFile).buffer) {
          buffer = (file as ExtendedFile).buffer;
          console.log(`使用提供的缓冲区，大小: ${buffer.length} 字节`);
        } else {
          throw new BadRequestException('无法识别的文件格式');
        }
      }
      
      const fileProcessTime = Date.now() - startTime;
      console.log(`主文件处理耗时: ${fileProcessTime}ms`);
    } catch (error) {
      console.error('处理主文件时出错:', error);
      throw new BadRequestException(`处理文件时出错: ${error.message}`);
    }
    
    console.log('处理封面图片...');
    // 处理封面图片
    let coverOriginalName = '', coverBuffer;
    const coverStartTime = Date.now();
    
    try {
      // 如果是默认封面，使用内置的默认图片
      if (isDefaultCover) {
        try {
          // 尝试从默认封面文件夹加载封面
          const defaultCoverPath = path.join(__dirname, '../../../../../public/default', 'default-cover.jpg');
          
          try {
            // 尝试读取默认封面文件
            coverBuffer = await fs.promises.readFile(defaultCoverPath)
              .catch(() => {
                // 如果文件不存在，创建一个1x1像素的图片
                console.log('默认封面文件不存在，创建一个1x1像素图片');
                return Buffer.from([
                  0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x48, 
                  0x00, 0x48, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC2, 0x00, 0x0B, 0x08, 0x00, 0x01, 0x00, 0x01, 
                  0x01, 0x01, 0x11, 0x00, 0xFF, 0xC4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 
                  0x00, 0x01, 0x3F, 0x10
                ]);
              });
            
            coverOriginalName = 'default-cover.jpg';
            console.log(`使用默认封面，大小：${coverBuffer.length} 字节`);
          } catch (err) {
            console.error('读取默认封面出错:', err);
            throw new BadRequestException('无法读取默认封面');
          }
        } catch (defaultCoverError) {
          console.error('处理默认封面时出错:', defaultCoverError);
          throw new BadRequestException('处理默认封面时出错');
        }
      }
      // 处理标准MultipartFile对象
      else if (typeof cover.toBuffer === 'function') {
        coverOriginalName = cover.filename;
        coverBuffer = await cover.toBuffer();
        console.log(`标准封面对象处理完成，文件名: ${coverOriginalName}, 缓冲区大小: ${coverBuffer.length} 字节`);
      }
      // 处理JSON格式的文件对象
      else {
        coverOriginalName = (cover as ExtendedFile).name || cover.filename || 'unknown';
        console.log(`非标准封面对象，使用名称: ${coverOriginalName}`);
        
        // 如果前端提供的是base64字符串
        if ((cover as ExtendedFile).base64) {
          const base64Data = (cover as ExtendedFile).base64?.split(';base64,').pop() || '';
          coverBuffer = Buffer.from(base64Data, 'base64');
          console.log(`从base64创建封面缓冲区，大小: ${coverBuffer.length} 字节`);
        }
        // 如果前端提供的是Buffer或其他格式
        else if ((cover as ExtendedFile).buffer) {
          coverBuffer = (cover as ExtendedFile).buffer;
          console.log(`使用提供的封面缓冲区，大小: ${coverBuffer.length} 字节`);
        } else {
          throw new BadRequestException('无法识别的封面格式');
        }
      }
      
      const coverProcessTime = Date.now() - coverStartTime;
      console.log(`封面处理耗时: ${coverProcessTime}ms`);
    } catch (error) {
      console.error('处理封面时出错:', error);
      throw new BadRequestException(`处理封面时出错: ${error.message}`);
    }
    
    console.log('检查文件类型和格式...');
    const extName = getExtname(originalName)
    const currentDate = format(new Date(), 'yyyyMMdd')
    const fileName = fileRename(originalName)
    
    // 检查文件类型
    const fileType = getFileType(extName)
    const isVideo = fileType === '视频'
    const isAudio = fileType === '音乐'
    let workType = uploadWorkDto.workType
    
    console.log(`文件类型: ${fileType}, 扩展名: ${extName}, 工作类型: ${workType}`);
    
    // 检查文件类型与作品类型是否匹配
    if (workType === WorkType.Video && !isVideo) {
      throw new BadRequestException('视频作品请上传视频文件')
    }
    
    if (workType === WorkType.Audio && !isAudio) {
      throw new BadRequestException('音频作品请上传音频文件')
    }
    
    // 自动判断作品类型
    if (isVideo) {
      workType = WorkType.Video
      console.log('自动设置为视频作品类型');
    } else if (isAudio) {
      workType = WorkType.Audio
      console.log('自动设置为音频作品类型');
    }

    const coverExtName = getExtname(coverOriginalName)
    const coverFileName = fileRename(coverOriginalName)
    
    // 检查封面文件类型
    const coverFileType = getFileType(coverExtName)
    const isCoverImage = coverFileType === '图片' || isDefaultCover
    
    console.log(`封面类型: ${coverFileType}, 扩展名: ${coverExtName}, 是否图片: ${isCoverImage}`);
    
    if (!isCoverImage) {
      throw new BadRequestException('封面必须是图片文件（jpg, jpeg, png, gif）')
    }
    
    try {
      console.log('开始保存文件...');
      const saveStartTime = Date.now();
      
      // 保存作品文件到本地
      await saveLocalFile(buffer, fileName, currentDate, fileType)
      console.log(`主文件已保存到本地，文件名: ${fileName}`);
      
      // 保存封面文件到本地
      await saveLocalFile(coverBuffer, coverFileName, currentDate, '图片')
      console.log(`封面已保存到本地，文件名: ${coverFileName}`);
      
      const saveTime = Date.now() - saveStartTime;
      console.log(`文件保存耗时: ${saveTime}ms`);
      
      // 获取文件URL
      const fileUrl = getFilePath(fileName, currentDate, fileType)
      
      // 获取封面URL
      const thumbnailUrl = getFilePath(coverFileName, currentDate, '图片')
      
      console.log('构造作品数据并创建数据库记录...');
      // 构造作品数据
      const createWorkDto: CreateWorkDto = {
        ...uploadWorkDto,
        workType,
        fileUrl,
        thumbnailUrl,
        status: WorkStatus.Normal, // 确保所有上传的作品状态为"普通"
      }
      
      console.log(`将使用以下数据创建作品: 标题="${createWorkDto.workTitle}", 类型=${createWorkDto.workType}, 学生ID=${createWorkDto.studentId}`);
      
      // 创建作品
      const work = await this.create(createWorkDto);
      console.log(`作品创建成功，ID: ${work.workId}`);
      return work;
    } catch (error) {
      console.error('文件上传过程中出错:', error);
      throw new BadRequestException(`文件上传失败: ${error.message}`)
    }
  }

  /**
   * 为作品添加评论
   */
  async addComment(createCommentDto: CreateCommentDto): Promise<WorkCommentEntity> {
    // 检查作品是否存在
    const work = await this.workRepository.findOne({
      where: { id: createCommentDto.workId, isDelete: 0 }
    })

    if (!work) {
      throw new NotFoundException(`作品ID为${createCommentDto.workId}的记录不存在`)
    }

    // 如果有父评论，检查父评论是否存在
    if (createCommentDto.parentId) {
      const parentComment = await this.workCommentRepository.findOne({
        where: { id: createCommentDto.parentId, isDelete: 0 }
      })

      if (!parentComment) {
        throw new NotFoundException(`评论ID为${createCommentDto.parentId}的记录不存在`)
      }
    }

    // 创建评论
    const comment = this.workCommentRepository.create(createCommentDto)
    return this.workCommentRepository.save(comment)
  }

  /**
   * 获取作品评论列表
   */
  async getComments(workId: number): Promise<WorkCommentEntity[]> {
    // 查询作品评论
    const comments = await this.workCommentRepository.find({
      where: { workId, isDelete: 0 },
      order: { createdAt: 'DESC' }
    })

    // 获取评论者信息
    if (comments.length > 0) {
      // 获取所有用户ID
      const userIds = [...new Set(comments.map(comment => comment.userId))]
      
      // 查询用户信息
      const studentIds = []
      const teacherIds = []
      
      comments.forEach(comment => {
        if (comment.userType === 1) { // 学生
          studentIds.push(comment.userId)
        } else { // 教师
          teacherIds.push(comment.userId)
        }
      })
      
      // 查询学生信息
      const students = studentIds.length > 0 ? await this.workRepository.manager.query(
        `SELECT id, student_id as studentId, user_name as userName
         FROM c_student 
         WHERE id IN (?) AND is_delete = 0`,
        [studentIds]
      ) : []
      
      // 查询教师信息
      const teachers = teacherIds.length > 0 ? await this.workRepository.manager.query(
        `SELECT id, nickname as userName
         FROM sys_user 
         WHERE id IN (?)`,
        [teacherIds]
      ) : []
      
      // 构建用户映射
      const userMap = {}
      students.forEach(student => {
        userMap[`1_${student.id}`] = student
      })
      
      teachers.forEach(teacher => {
        userMap[`2_${teacher.id}`] = teacher
      })
      
      // 为评论添加用户信息
      comments.forEach(comment => {
        const key = `${comment.userType}_${comment.userId}`
        comment['user'] = userMap[key] || { userName: '未知用户' }
      })
    }

    return comments
  }

  /**
   * 删除评论
   */
  async removeComment(id: number): Promise<void> {
    const comment = await this.workCommentRepository.findOne({
      where: { id, isDelete: 0 }
    })

    if (!comment) {
      throw new NotFoundException(`评论ID为${id}的记录不存在`)
    }

    // 逻辑删除评论
    await this.workCommentRepository.update(id, { isDelete: 1 })
    
    // 逻辑删除所有子评论
    await this.workCommentRepository.update({ parentId: id, isDelete: 0 }, { isDelete: 1 })
  }

  /**
   * 点赞作品
   */
  async likeWork(id: number): Promise<WorkEntity> {
    const work = await this.findOne(id)
    
    // 增加点赞次数
    await this.workRepository.update(id, {
      likeCount: work.likeCount + 1
    })
    
    return this.findOne(id)
  }

  /**
   * 切换作品状态（普通/冠军）
   */
  async toggleWorkStatus(id: number): Promise<WorkEntity> {
    const work = await this.findOne(id)
    
    // 切换状态：普通 -> 冠军, 冠军 -> 普通
    const newStatus = work.status === WorkStatus.Normal ? WorkStatus.Champion : WorkStatus.Normal
    
    // 更新作品状态
    await this.workRepository.update(id, { status: newStatus })
    
    return this.findOne(id)
  }

  /**
   * 批量切换作品状态
   */
  async batchToggleWorkStatus(ids: number[]): Promise<WorkEntity[]> {
    if (!ids || ids.length === 0) {
      throw new BadRequestException('作品ID列表不能为空')
    }
    
    // 获取所有作品当前状态
    const works = await this.workRepository.find({
      where: { id: In(ids), isDelete: 0 }
    })
    
    if (works.length === 0) {
      throw new NotFoundException('未找到有效的作品')
    }
    
    // 逐个切换状态
    for (const work of works) {
      const newStatus = work.status === WorkStatus.Normal ? WorkStatus.Champion : WorkStatus.Normal
      await this.workRepository.update(work.id, { status: newStatus })
    }
    
    // 返回更新后的作品列表
    return this.workRepository.find({
      where: { id: In(ids), isDelete: 0 }
    })
  }
}
